package com.xiaoshuidi.cloud.module.iot.service.impl;

import cn.com.ake.AnyType2AnyTypeMap;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.AmmeterInfoResModel;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.WaterMeterCommonResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.DeviceGetDailyPowerResModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.PullThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DeviceRepository;
import com.xiaoshuidi.cloud.module.iot.enums.BrandEnum;
import com.xiaoshuidi.cloud.module.iot.enums.DeviceTypeEnum;
import com.xiaoshuidi.cloud.module.iot.service.AbstractThirdInstanceService;
import com.xiaoshuidi.cloud.module.iot.uitils.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Service("aikeInstanceService")
@Slf4j
public class AikeInstanceServiceImpl extends AbstractThirdInstanceService {
    private final static Logger LOGGER = LoggerFactory.getLogger(AikeInstanceServiceImpl.class);
    //获取token
    @Value("${aike.getToken.url}")
    private String aikeGetTokenUrl;
    @Value("${aike.getDevices.url}")
    private String aikeGetDevicesUrl;
    @Value("${aike.getDeviceInfo.url}")
    private String aikeGetDeviceInfoUrl;
    @Value("${aike.controlCommand.url}")
    private String controlCommandUrl;
    @Value("${aike.systemCode}")
    private String systemCode;

    @Autowired
    private DeviceRepository deviceDataAccess;


    @Override
    public String getBrand() {
        return BrandEnum.AIKE.getBrand();
    }

    @Override
    public AccessTokenResponseModel getAccessToken(AccessTokenRequestModel accessTokenRequestModel) throws Exception {
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        Map header=new HashMap<>();
        Map params=new HashMap<>();
        header.put("Content-Type","application/x-www-form-urlencoded");
        params.put("client_id", accessTokenRequestModel.getAppId());
        params.put("client_secret", accessTokenRequestModel.getAppKey());
        LOGGER.info("艾科获取access_token，请求url:{},请求参数:{}", aikeGetTokenUrl, params.toString());
//        String result = HttpRequest.get(aikeGetTokenUrl).body(JSONObject.toJSONString(params)).header("Content-Type","application/x-www-form-urlencoded").execute().body();
        String result = HttpRequest.get(aikeGetTokenUrl).form(params).header("Content-Type","application/x-www-form-urlencoded").execute().body();
        LOGGER.info("艾科获取access_token,返回结果:{}", result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject resultJsonObject = JSONObject.parseObject(result);
            //艾科访问凭证
            String access_token = resultJsonObject.getString("access_token");
            //艾科返回的失效时间（秒）
            Long expires_time = resultJsonObject.getLong("expires_time");
            accessTokenResponseModel.setAccessToken(access_token);
            accessTokenResponseModel.setExpireTime(expires_time);
        }
        //第三方业务返回逻辑处理,返回获取的token
        return accessTokenResponseModel;
    }

    @Override
    public List<TbDeviceDo> getDevice(PullThirdDeviceRequestModel pullThirdDeviceRequestModel) throws Exception {
        List<TbDeviceDo> tbDeviceDoList = Lists.newArrayList();
        try{
            Map header=new HashMap<>();
            Map params=new HashMap<>();
            header.put("Content-Type","application/x-www-form-urlencoded");
            //catCode为区分水表和电表，null则为拉取所有设备
            //params.put("catCode",null); 此处不能传null，aike接收为"null",无法返回数据，不传则返回所有设备
            LOGGER.info("艾科获取设备列表，请求url:{},请求参数:{}", aikeGetDevicesUrl, params.toString());
            String result = HttpRequest.get(aikeGetDevicesUrl).body(JSONObject.toJSONString(params)).header("Content-Type","application/x-www-form-urlencoded").execute().body();
            LOGGER.info("艾科获取设备列表,返回结果:{}", result);
            if (StringUtils.isNotBlank(result)) {
                JSONObject resultJsonObject = JSONObject.parseObject(result);
                String errMsg = resultJsonObject.getString("ErrMsg");
                if(StringUtils.isNotBlank(errMsg) && errMsg.equals("成功")){
                    JSONArray allDataArray = resultJsonObject.getJSONArray("data");
                    for (Iterator<Object> dataIterator = allDataArray.iterator(); dataIterator.hasNext(); ) {
                        JSONObject dataJson = (JSONObject) dataIterator.next();
                        TbDeviceDo tbDeviceDo = new TbDeviceDo();
                        String meterCode = dataJson.getString("meterCode");
                        tbDeviceDo.setDeviceThirdNo(meterCode);
                        tbDeviceDo.setDeviceName(meterCode);
                        String catCode = dataJson.getString("catCode");
                        //电表和水表落库， 中继器什么的就不落库了
                        if("水表".equals(catCode) || "电表".equals(catCode)){
                            switch (catCode){
                                case "水表":
                                    tbDeviceDo.setDeviceType(DeviceTypeEnum.COLD_WATERMETE_TYPE_ENUM.getCode());
                                    break;
                                case "电表":
                                    tbDeviceDo.setDeviceType(DeviceTypeEnum.AMMETER.getCode());
                                    break;
                            }
                        }else{
                            continue;
                        }
                        //tbDeviceDo.setCreateUser(10001);
                        //无返回，默认在线
                        tbDeviceDo.setOnlineStatus(1);
                        //设备型号
                        String model = dataJson.getString("model");
                        tbDeviceDo.setDeviceModel(model);
                        tbDeviceDo.setReportTime(LocalDateTime.now());
                        tbDeviceDoList.add(tbDeviceDo);
                    }
                }else{
                    LOGGER.info("艾科获取设备列表失败，问问艾科咋肥四");
                }
                return tbDeviceDoList;
            }
        }catch(Exception e){
            LOGGER.info("艾科获取设备列表异常:{}",e.getMessage());
            throw e;
        }
        return tbDeviceDoList;
    }

    @Override
    public List<TbDeviceDo> initializeDeviceInfo(List<TbDeviceDo> thirdDeviceList, PullThirdDeviceRequestModel pullThirdDeviceRequestModel) {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel addDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel getDynamicDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public AmmeterInfoResModel refreshAmmeterInfo(TbDeviceDo tbDeviceDo, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        LOGGER.info("艾科刷新电表，请求url:{},请求参数->device_third_no:{},access_token:{}", aikeGetDeviceInfoUrl, tbDeviceDo.getDeviceThirdNo(),operateThirdDeviceRequestModel.getAccessToken());
        AmmeterInfoResModel ammeterInfoResModel = new AmmeterInfoResModel();
        String result = this.getDeviceInfo(operateThirdDeviceRequestModel.getAccessToken(), tbDeviceDo.getDeviceThirdNo());
        JSONObject jsonObject = JSONObject.parseObject(result);
        if(jsonObject.getString("ErrMsg").equals("成功")){
            JSONArray allDataArray = jsonObject.getJSONArray("data");
            for (Iterator<Object> dataIterator = allDataArray.iterator(); dataIterator.hasNext(); ) {
                JSONObject dataJson = (JSONObject) dataIterator.next();
                String errMsg = dataJson.getString("ErrMsg");
                String errNo = dataJson.getString("ErrNo");
                if("成功".equals(errMsg) && "0".equals(errNo)){
                    JSONObject data = dataJson.getJSONObject("data");
                    //当前度数
                    String positiveElec = data.getString("PositiveElec");
                    String elecValue = data.getString("ElecValue");
                    String switchState = data.getString("switchState");
                    if(null != elecValue){
                        ammeterInfoResModel.setCurrentReading(Double.parseDouble(elecValue));
                    }
                    if(null != positiveElec){
                        ammeterInfoResModel.setCurrentReading(Double.parseDouble(positiveElec));
                    }
                    // 0合闸 1拉闸
                    if(StringUtils.isNotEmpty(switchState)){
                        if(switchState.equals("0")){
                            ammeterInfoResModel.setPowerStatus(1);
                        }else{
                            ammeterInfoResModel.setPowerStatus(0);
                        }
                    }
                    //在线
                    ammeterInfoResModel.setOnlineStatus(1);
                    String readingTime = data.getString("readingdt");
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date dateTime = dateFormat.parse(readingTime);
                    ammeterInfoResModel.setReportTime(dateTime);
                }
                if("15000".equals(errNo)){
                    ammeterInfoResModel.setOnlineStatus(0);
                }
            }
        }
        return ammeterInfoResModel;
    }

    @Override
    public List<DeviceGetDailyPowerResModel> getDailyPower(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel)  {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel updateDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel frozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel unfrozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        Long timestamp = System.currentTimeMillis();
        TbDeviceDo deviceByDeviceThirdNo = deviceDataAccess.getDeviceByDeviceThirdNo(operateThirdDeviceRequestModel.getDeviceThirdNo());
        StringBuilder str = new StringBuilder();
        str.append("{\"cmdgroup\":[{\"cmdid\":1,\"segment\":[]}],\"cmdid\":1,\"gwid\":\"127.0.0.1\",\"iscmdgrp\":0,\"metercode\":\"");
        str.append(operateThirdDeviceRequestModel.getDeviceThirdNo());
        str.append("\",\"model\":\"");
        str.append(deviceByDeviceThirdNo.getDeviceModel());
        str.append("\",\"sessionid\":\"\",\"timeout\":30,\"type\":\"metercmd\"}");
        String s = str.toString();
        String key = MD5Util.MD5Encode("AKE1997str" + s + "timestamp" + timestamp + systemCode);
        LOGGER.info("向艾科发起拉闸/关阀请求，str:{},key:{},timestamp:{}",s,key,timestamp);
        JSONObject jsonObject = this.executeControlCommand(s, key, timestamp);
        LOGGER.info("艾科拉闸/关阀返回:{}",jsonObject.toJSONString());
        if(null != jsonObject){
            String status = jsonObject.getString("status");
            String msg = jsonObject.getString("data");
            if("1".equals(status)){
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setOperateMessage("合闸成功");
            }else {
                operateThirdDeviceResponseModel.setOperateResult(false);
                operateThirdDeviceResponseModel.setOperateMessage("合闸失败");
            }
        }else{
            operateThirdDeviceResponseModel.setOperateResult(false);
            operateThirdDeviceResponseModel.setOperateMessage("与艾科通讯网络异常");
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        Long timestamp = System.currentTimeMillis();
        TbDeviceDo deviceByDeviceThirdNo = deviceDataAccess.getDeviceByDeviceThirdNo(operateThirdDeviceRequestModel.getDeviceThirdNo());
        StringBuilder str = new StringBuilder();
        str.append("{\"cmdgroup\":[{\"cmdid\":1,\"segment\":[]}],\"cmdid\":2,\"gwid\":\"127.0.0.1\",\"iscmdgrp\":0,\"metercode\":\"");
        str.append(operateThirdDeviceRequestModel.getDeviceThirdNo());
        str.append("\",\"model\":\"");
        str.append(deviceByDeviceThirdNo.getDeviceModel());
        str.append("\",\"sessionid\":\"\",\"timeout\":30,\"type\":\"metercmd\"}");
        String s = str.toString();
        String key = MD5Util.MD5Encode("AKE1997str" + s + "timestamp" + timestamp + systemCode);
        LOGGER.info("向艾科发起拉闸/关阀请求，str:{},key:{},timestamp:{}",s,key,timestamp);
        JSONObject jsonObject = this.executeControlCommand(s, key, timestamp);
        LOGGER.info("艾科拉闸/关阀返回:{}",jsonObject.toJSONString());
        if(null != jsonObject){
            String status = jsonObject.getString("status");
            String msg = jsonObject.getString("data");
            if("1".equals(status)){
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setOperateMessage("拉闸成功");
            } else {
                operateThirdDeviceResponseModel.setOperateResult(false);
                operateThirdDeviceResponseModel.setOperateMessage("拉闸失败");
            }
        }else{
            operateThirdDeviceResponseModel.setOperateResult(false);
            operateThirdDeviceResponseModel.setOperateMessage("与艾科通讯网络异常");
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel deleteDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public WaterMeterCommonResponseModel refreshWatermeterInfo(WaterMeterCommonResponseModel waterMeterCommonResponseModel, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String result = this.getDeviceInfo(operateThirdDeviceRequestModel.getAccessToken(), waterMeterCommonResponseModel.getDeviceThirdNo());
        JSONObject jsonObject = JSONObject.parseObject(result);
        if(jsonObject.getString("ErrMsg").equals("成功")){
            JSONArray allDataArray = jsonObject.getJSONArray("data");
            for (Iterator<Object> dataIterator = allDataArray.iterator(); dataIterator.hasNext(); ) {
                JSONObject dataJson = (JSONObject) dataIterator.next();
                String errMsg = dataJson.getString("ErrMsg");
                String errNo = dataJson.getString("ErrNo");
                if("成功".equals(errMsg) && "0".equals(errNo)){
                    waterMeterCommonResponseModel.setOperateResult(true);
                    JSONObject data = dataJson.getJSONObject("data");
                    //当前度数
                    String currentReading = data.getString("AccumulateFlux");
                    waterMeterCommonResponseModel.setCurrentReading(Double.parseDouble(currentReading));
                    //在线
                    waterMeterCommonResponseModel.setOnlineStatus(1);
                    String readingTime = data.getString("readingdt");
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date dateTime = dateFormat.parse(readingTime);
                    waterMeterCommonResponseModel.setReportTime(dateTime);
                }
                if("15000".equals(errNo)){
                    waterMeterCommonResponseModel.setOnlineStatus(0);
                }
            }
        }
        return waterMeterCommonResponseModel;
    }
    @Override
    public OperateThirdDeviceResponseModel getDoorLockStatus(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel getOpenLockRecordes(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    /**
     * 获取设备详细信息
     */
    private String getDeviceInfo(String accessToken,String uuid){
        try{
            Map header=new HashMap<>();
            Map params=new HashMap<>();
            header.put("Content-Type","application/x-www-form-urlencoded");
            params.put("access_token",accessToken);
            params.put("uuid",uuid);
            LOGGER.info("艾科获取设备信息，请求url:{},请求参数:{}", aikeGetDeviceInfoUrl, params.toString());
            String result = HttpRequest.get(aikeGetDeviceInfoUrl).form(params).header("Content-Type","application/x-www-form-urlencoded").execute().body();
            LOGGER.info("艾科获取设备信息,返回结果:{}", result);
            return result;
        }catch (Exception e){
            LOGGER.info("艾科获取设备信息异常,异常信息:{}",e.getMessage());
            throw e;
        }
    }

    /**
     * <li>远程控制指令，对仪表进行控制
     * @param str 指令段参数
     * @param key 参数签名
     * @param timestamp 时间戳
     * @return 结果内容
     */
    public JSONObject executeControlCommand(String str,String key,long timestamp) throws Exception {
        JSONObject jsonObject = new JSONObject();
        // 创建动态客户端工厂
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        // 创建客户端
        Client client = dcf.createClient(controlCommandUrl);
        // 调用远程方法
        Object[] response = client.invoke("executeControlCommand", str, key, timestamp);
        LOGGER.info("请求艾科url:{},返回结果：{}",controlCommandUrl,JSONObject.toJSONString(response));
        // 根据返回值类型进行相应的处理
        Object result = response[0];
        AnyType2AnyTypeMap result1 = (AnyType2AnyTypeMap) result;
        List<AnyType2AnyTypeMap.Entry> entryList = result1.getEntry();
        for (AnyType2AnyTypeMap.Entry amap : entryList){
            String key1 = (String)amap.getKey();
            Object value = amap.getValue();
            jsonObject.put(key1,value);
        }
        return jsonObject;
    }

}
